import datetime
import json
import random
import sys
import time

from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By

from libs import config
from libs.action import WebDriverAction
from libs.game import Game
from libs.image import ImageTool
from libs.log import Log
from libs.movement import Movement
from libs.task_helper import TaskHelper
from libs.trade_helper import TradeHelper
from libs.window import AdsWindow


def drink_popberry_wine(energy_target):
    log.info(f"drink energy start: energy={game.get_energy()}, need {energy_target}")
    home_loc = action.goto_spec()
    game.open_backpack()
    wine_loc = image_tool.find_target('popberry_wine.png')
    if wine_loc is None:
        log.info('popberry wine not found')
    else:
        wine_x, wine_y = wine_loc
        action.click_by_offset(wine_x + 20, wine_y + 20)

        before_drink_energy = game.get_energy()
        no_effect_count = 0
        while True:
            if energy_target - game.get_energy() < 77:
                log.debug('energy full')
                action.escape()
                break
            home_x, home_y = home_loc
            action.move_by_offset(home_x + 45, home_y + 180)
            action.click()
            time.sleep(1)
            after_drink_energy = game.get_energy()
            if after_drink_energy - before_drink_energy > 10:
                before_drink_energy = after_drink_energy
                continue
            else:
                # 体力没增加
                log.debug('drink no effect')
                no_effect_count += 1
                if no_effect_count > 2:
                    action.escape()
                    break
                continue
    log.info(f"drink energy end: energy={game.get_energy()}")
    time.sleep(1)
    game.close_backpack()


def collect(offset_x, offset_y):
    global tb_loc
    tb_x, tb_y = tb_loc
    if action.hover_bubble_text_is(tb_x + offset_x, tb_y + offset_y, 'Ready to Collect'):
        action.click()
        time.sleep(0.5)


def cook(offset_x, offset_y):
    global tb_loc
    global log_index

    tb_x, tb_y = tb_loc
    if action.hover_bubble_text_is(tb_x + offset_x, tb_y + offset_y, 'Add 1 Log'):
        game.use_backpack_item(log_index)
        time.sleep(0.5)
        action.click()
        action.escape()
        time.sleep(0.5)
    if action.hover_bubble_text_is(tb_x + offset_x, tb_y + offset_y, 'Click to Cook'):
        action.click()
        time.sleep(1)
        opt = action.find_element(By.XPATH, f"//span[text()='{cooking_item_name}']", cooking_item_name, 3)
        if opt is None:
            action.escape()
            time.sleep(1)
            action.click()
            opt = action.find_element(By.XPATH, f"//span[text()='{cooking_item_name}']", cooking_item_name, 10)
        opt.click()
        action.click_by_offset(440, 540)
        time.sleep(0.5)
        action.escape()
        time.sleep(0.5)
        return 1
    return 0


def get_sell_price(order_items):
    target_price = None
    price_and_qty = {}

    for item in order_items:
        item_price = trade_helper.get_number(item.text.split(' @ ')[1])
        item_qty = trade_helper.get_number(item.text.split(' ')[0])
        price_and_qty[item_price] = price_and_qty.get(item_price, 0) + item_qty

    for price in price_and_qty:
        qty = price_and_qty.get(price)
        if qty < 33:
            continue
        elif qty < 100:
            target_price = int(price)
            break
        else:
            target_price = int(price) - 1
            break
    return target_price


def get_avg_buy_price(order_items, buy_qty):
    total_qty = 0
    total_cost = 0
    for item in order_items:
        price = trade_helper.get_number(item.text.split(' @ ')[1])
        qty = trade_helper.get_number(item.text.split(' ')[0])
        total_qty += qty
        total_cost += qty * price
        if total_qty > buy_qty:
            break
    return int(total_cost / total_qty)


def cook_grumpkin():
    global tb_loc
    global log_index
    cooking_count = 33
    energy_cost = cooking_item.get('energy_cost')
    if game.get_energy() < cooking_count * energy_cost + 10:
        log.debug('energy not enough')
        return False
    # calculate profit
    trade_helper.goto_buy_position()
    filter_input = trade_helper.open_market_buy()
    _, puree_items = trade_helper.open_order_items(filter_input, 'Blue Grumpkin Puree')
    puree_price = get_avg_buy_price(puree_items, cooking_count * 3)
    action.escape()
    _, flour_items = trade_helper.open_order_items(filter_input, flour_name)
    flour_price = get_avg_buy_price(flour_items, cooking_count * 2)
    action.escape()
    _, loaf_items = trade_helper.open_order_items(filter_input, 'Blue Grumpkin Loaf')
    loaf_price = get_sell_price(loaf_items)
    action.escape()
    action.escape()
    profit = loaf_price - puree_price * 3 - flour_price * 2
    log.info(json.dumps({
        'energy': game.get_energy(),
        'puree': puree_price,
        'flour': flour_price,
        'loaf': loaf_price,
        'profit': profit
    }))

    game.get_backpack()
    flour_qty = game.get_backpack_qty(flour_name)
    if flour_qty == 0 and profit < 5:
        log.info('no profit, give_up')
        return False
    else:
        # 购买材料
        buy_items = {}
        log_item_name = 'Whittlewood Log'
        log_index, log_qty = game.get_backpack_index_and_qty(log_item_name)
        if log_qty < 20:
            buy_items[log_item_name] = 99 - log_qty
        need_items = cooking_item.get('items', {})
        for item_name in need_items:
            need_qty = need_items.get(item_name) * cooking_count
            bp_qty = game.get_backpack_qty(item_name)
            if need_qty > bp_qty:
                buy_items[item_name] = need_qty - bp_qty

        if len(buy_items) > 0:
            trade_helper.goto_buy_position()
            filter_input = trade_helper.open_market_buy()
            for buy_item_name in buy_items:
                buy_item_qty = buy_items.get(buy_item_name)
                trade_helper.market_buy_item(filter_input, buy_item_name, buy_item_qty)
            action.escape()
            time.sleep(0.5)
            action.escape()
            time.sleep(1)

        # 做loaf
        action.goto_task_board()
        movement.keep_move_left(2.5)
        time.sleep(1)
        finish_count = 0
        for _ in range(int(cooking_count / 12) + 1):
            if finish_count >= cooking_count:
                break
            # 点火，烹饪
            tb_loc = image_tool.find_target('task_board.png')
            for x in offset_x1s:
                for y in offset_ys:
                    collect(x, y)
                    if finish_count < cooking_count:
                        finish_count += cook(x, y)

            movement.keep_move_right(1)
            time.sleep(1)
            tb_loc = image_tool.find_target('task_board.png')
            for x in offset_x2s:
                for y in offset_ys:
                    collect(x, y)
                    if finish_count < cooking_count:
                        finish_count += cook(x, y)
            time.sleep(2)
            movement.keep_move_left(1)
            time.sleep(1)
            log.debug(f"{finish_count}/{cooking_count} made")

        # collect
        tb_loc = image_tool.find_target('task_board.png')
        for x in offset_x1s:
            for y in offset_ys:
                collect(x, y)

        movement.keep_move_right(1)
        time.sleep(1)
        tb_loc = image_tool.find_target('task_board.png')
        for x in offset_x2s:
            for y in offset_ys:
                collect(x, y)
        # sell loaf
        trade_helper.goto_buy_position()
        loaf_name = cooking_item.get('sell_item_name')
        loaf_qty = cooking_count * 2
        buy_filter_input = trade_helper.open_market_buy()
        _, loaf_order_items = trade_helper.open_order_items(buy_filter_input, loaf_name)
        sell_price = get_sell_price(loaf_order_items)
        action.escape()
        action.escape()
        trade_helper.buy_to_sell()
        trade_helper.open_shop_sell()
        trade_helper.sell_item(
            loaf_name,
            loaf_qty,
            sell_price=sell_price,
            price_delta=-1,
            min_price=cooking_item.get('min_price')
        )
        time.sleep(1)
        action.escape()
        time.sleep(10)
        trade_helper.sell_to_buy()
        coin_losing = False
        for _ in range(6):
            game.collect_mail()
            current_coin = game.get_coin()
            log.info(f'start_coin={start_coin}, current_coin={current_coin}')
            # 判断当前资金损耗是否大于10万
            if start_coin - current_coin > 100000:
                coin_losing = True
                time.sleep(10)
            else:
                coin_losing = False
                break
        if coin_losing:
            log.info(f'coin lost more than 100000, give_up')
            return False
        movement.keep_move_right(2)
        return True


if __name__ == "__main__":
    parser = TaskHelper.default_args_parser('Cooking Grumpkin')
    args = parser.parse_args()
    task_helper = TaskHelper.from_args(args)

    user_id = args.user_id
    log = Log(user_id)
    try:
        # 启动窗口
        driver = AdsWindow(user_id).open(False)
        action = WebDriverAction(driver, debug=False)
        movement = Movement(driver)
        ac = ActionChains(driver)
        image_tool = ImageTool(driver)
        game = Game(driver, user_id)
        # 进入游戏
        game.enter_game()
        game.snapshot(user_id, 'before cooking_grumpkin')
        log.info(f'cooking grumpkin loaf start')

        item_key = 'grumpkin_loaf'
        flour_name = 'Grainbow Flour'
        cooking_item = config.get_cooking_item(item_key)
        cooking_item_name = cooking_item.get('name')
        offset_x1s = [-460, -330]
        offset_x2s = [-200, -70]
        offset_ys = [-155, -30, 110]

        trade_helper = TradeHelper(driver, user_id)
        loaf_name = cooking_item.get('sell_item_name')
        # 卖掉popberry相关的成品
        pop_items = {
            "Popberry Loaf": 300,
            "Popberry Jam": 40,
        }
        game.get_backpack()
        if len(pop_items) > 0:
            trade_helper.goto_sell_position()
            trade_helper.open_shop_sell()
            for sell_item_name in pop_items:
                qty = game.get_backpack_qty(sell_item_name)
                if qty > 0:
                    min_price = pop_items.get(sell_item_name)
                    trade_helper.sell_item(sell_item_name, qty, min_price)

        time.sleep(1)
        action.escape()
        time.sleep(20)
        game.collect_mail()
        start_coin = game.get_coin()
        log.info(f'start coin={start_coin}')
        tb_loc = None
        log_index = None
        target_energy = 500
        if target_energy - game.get_energy() >= 77:
            # 喝酒
            drink_popberry_wine(target_energy)

        for _ in range(10):
            try:

                if not cook_grumpkin():
                    break
            except Exception as e:
                print(e)
                continue

        time.sleep(30)
        game.collect_mail()
        game.snapshot(user_id, 'cooking grumpkin loaf end')
        task_helper.cooking_grumpkin(delay_seconds=random.randint(60 * 60 * 6, 60 * 60 * 8))
        task_helper.task_success()

    except Exception as e:
        log.info('error occurred')
        task_helper.task_fail()
        task_helper.cooking_grumpkin(retry=True)
        raise e
